<template>
  <section>
    <el-alert
      :style="{
        marginBottom: '8px'
      }"
      v-show="alertMessage"
      :title="alertMessage"
      type="error"
      show-icon
    ></el-alert>
    <el-upload
      :limit="limit"
      :action="action"
      :data="getData"
      :name="name"
      drag
      multiple
      :file-list="fileList"
      :headers="headers"
      :on-success="onSuccess"
      :before-upload="beforeUpload"
      :on-progress="uploadProcess"
      :on-exceed="onExceed"
      :on-remove="onRemove"
      :http-request="httpRequest"
      :on-error="onError"
    >
      <i class="el-icon-upload"></i>
      <div class="el-upload__text">
        将文件拖到此处，或
        <em>点击上传</em>
      </div>
      <div class="el-upload__tip" slot="tip">
        <slot name="tip"></slot>
      </div>
    </el-upload>
  </section>
</template>

<script lang="ts">
import { Component, Vue, Prop, Emit } from "vue-property-decorator";
import { State, namespace } from "vuex-class";
import { getTokenFormLocal } from "@/utils/Storage";
import { API_ASSETS_FILE } from "@/api";
import ossUpload from "@/utils/ossForUpload.ts";
import { EventBus } from "feok-lib";

/**
 * 文件上传
 *
 * @param {string} action - 上传的地址
 * @param {object} data - 上传时附带的额外参数
 * @param {string} name - 上传的文件字段名
 * @param {object} headers - 设置上传的请求头部
 * @param {number} maxSize - 文件上传的大小上限 单位kb
 * @param {number} limit - 最大允许上传个数
 * @param {array} fileTypes - 上传文件的类型
 * @param {array} fileList - 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
 *
 * @event on-success - 文件上传成功时的钩子 function(response, file, fileList)
 * @event on-remove - 文件列表移除文件时的钩子 function(file, fileList)
 * @event on-error - 文件上传错误 function(errorType, file) errorType: typeError 类型不匹配；overSize: 超出大小上线; exceed: 超出最大个数
 */

@Component
export default class OSSFileUpload extends Vue {
  get getData() {
    return {
      ...this.data
    };
  }

  @Prop({
    default() {
      return [];
    }
  })
  public fileTypes!: any[];
  @Prop({
    default() {
      return [];
    }
  })
  public fileList!: any[]; // 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
  @Prop({
    default() {
      return "";
    }
  })
  public action!: string; // 必选参数，上传的地址
  @Prop({
    default() {
      return {};
    }
  })
  public data!: object; // 上传时附带的额外参数
  @Prop() public name!: string; // 上传的文件字段名
  @Prop() public limit!: number; // 最大允许上传个数
  @Prop({ default: 2 * 1024 }) public maxSize!: number; // 文件上传的大小上线 单位kb // 2MB
  @Prop({
    default() {
      return {
        token: getTokenFormLocal() || ""
      };
    }
  })
  public headers!: object; // 设置上传的请求头部

  public httpRequest = ossUpload;
  public alertMessage = ""; // 错误信息

  @Emit("on-success")
  public onSuccess(response: any, file: any, fileList: any) {}

  /**
   * 文件列表移除文件时的钩子
   */
  @Emit("on-remove")
  public onRemove(file: any, fileList: any) {
    this.alertMessage = "";
  }

  public beforeUpload(file: any) {
    const fileName = file.name;
    const m = fileName.match(/\.(\w+)(#|\?|$)/);
    const fileType = (m && m[1]).toString().toLowerCase();

    const isImg = this.fileTypes.some((item: string) => fileType === item);
    const enabledSize = file.size / 1024;
    if (!isImg && this.fileTypes.length) {
      this.$nextTick(function() {
        this.alertMessage = `文件只能上传 ${this.fileTypes.join("、")} 格式`;
      });
      this.$emit("on-error", "文件格式不正确", file);
      return false;
    }
    if (enabledSize > this.maxSize) {
      this.$nextTick(function() {
        this.alertMessage = `文件大小不得超过${this.maxSize}kb`;
      });
      this.$emit("on-error", "文件太大了", file);
      return false;
    }
    this.alertMessage = "";
  }

  /**
   * 文件超出个数限制时的钩子
   */
  public onExceed(files: any, fileList: any) {
    this.alertMessage = `超出最大上传数量${this.limit}`;
    this.$emit("on-error", `上传最大数量${this.limit}`, files, fileList);
  }

  public onError(err: any, file: any, fileList: any) {
    this.alertMessage =
      process.env.NODE_ENV === "production"
        ? "网络异常，请稍后再试"
        : JSON.parse(err.message).msg;
    this.$emit(
      "on-error",
      "服务器端",
      JSON.parse(err.message).msg,
      file,
      fileList
    );
  }
  public uploadProcess(event: any, file: any, fileList: any) {
    EventBus.$emit("info", "导入中，请勿操作。");
  }
}
</script>

<style lang="less">
</style>